import { _decorator, IVec2, tween, Tween, Vec3 } from 'cc';
import { EntityManager } from '../../Base/EntityManager';
import { EntityTypeEnum, IBullet } from '../../Common';
import { EntityStateEnum, EventEnum } from '../../Enum';
import DataManager from '../../Global/DataManager';
import EventManager from '../../Global/EventManager';
import { ObjectPoolManager } from '../../Global/ObjectPoolManager';
import { radToAngle } from '../../Utils';
import { ExplosionManager } from '../Explosion/ExplosionManager';
import { BulletStateMachine } from './BulletStateMachine';
const { ccclass } = _decorator;

@ccclass("BulletManager")
export class BulletManager extends EntityManager {

    private targetPos: Vec3;
    private tw: Tween<unknown> = null;
    public type: EntityTypeEnum;
    public id: number;
    init(data: IBullet) {
        this.type = data.type;
        this.id = data.id;

        this.fsm = this.node.getComponent(BulletStateMachine) || this.addComponent(BulletStateMachine);
        this.fsm.init(data.type)

        this.targetPos = undefined;
        this.state = EntityStateEnum.Idle;
        this.node.active = false;
        this.initEvents();
    }

    initEvents() {
        EventManager.Instance.on(EventEnum.ExplosionBorn, this.handleExplosionBorn, this);
    }
    protected onDestroy(): void {
        EventManager.Instance.off(EventEnum.ExplosionBorn, this.handleExplosionBorn, this);
    }

    handleExplosionBorn(id: number, { x, y }: IVec2) {
        if (id !== this.id) {
            return;
        }

        const explosion = ObjectPoolManager.Instance.get(EntityTypeEnum.Explosion);
        const em = explosion.getComponent(ExplosionManager) || explosion.addComponent(ExplosionManager);
        em.init(EntityTypeEnum.Explosion, id, { x, y })

        DataManager.Instance.bulletMap.delete(this.id);
        this.reset();
        ObjectPoolManager.Instance.ret(this.node);
    }

    render(data: IBullet) {
        this.renderPos(data);
        this.renderDir(data);
    }

    renderPos(data: IBullet) {
        const { position } = data;
        const newPos: Vec3 = new Vec3(position.x, position.y)
        if (!this.targetPos) {
            this.node.active = true;
            this.node.setPosition(newPos);
            this.targetPos = new Vec3(newPos);
        } else if (!this.targetPos.equals(newPos)) {
            this.tw?.stop();
            this.node.setPosition(this.targetPos);
            this.targetPos.set(newPos);

            this.tw = tween(this.node)
                .to(0.1, { position: newPos })
                .start();
        }
        // this.node.setPosition(position.x, position.y);
    }

    renderDir(data: IBullet) {
        const { direction } = data;

        const side = Math.sqrt(direction.x ** 2 + direction.y ** 2);
        const angle = direction.x > 0 ? radToAngle(Math.asin(direction.y / side)) : (radToAngle(Math.asin(-direction.y / side)) + 180);

        this.node.setRotationFromEuler(0, 0, angle);
    }
    reset() {
        this.tw?.stop();
        this.fsm.reset();
        this.destroy();
    }
}